package org.example.httphandler;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

/**
 * @author 胡帅博
 * @date 2021/6/10 21:34
 */
public class RedirectRequestHandler implements HttpHandler{

    OkHttpClient client = new OkHttpClient();

    @Override
    public void handle(HttpExchange t) {
        //  testHandler( t);
        if (t.getRequestMethod().equals("GET")) {
            handleGet(t);
        } else {
            handlePost(t);
        }
    }

    private void handlePost(HttpExchange t) {
        System.out.println("post请求,暂未处理");
    }

    private void handleGet(HttpExchange t) {
        try {
            URI requestURI = t.getRequestURI();
            String params = requestURI.getRawQuery();
            String[] paramStr = params.split("&");
            Map map = new HashMap();

            for (int i = 0; i < paramStr.length; i++) {
                String p = paramStr[i];
                String[] kv = p.split("=", 2);
                if ("url".equals(kv[0])) {
                    kv[1] = URLDecoder.decode(kv[1], Charset.forName("utf-8"));
                }
                map.put(kv[0], kv[1]);
            }
            boolean needInject = false;

            Object needHook = map.get("needHook");
            if (needHook != null && Integer.valueOf(needHook.toString()).intValue() == 1) {
                needInject = true;
            }

            String url = map.get("url").toString();

            Headers requestHeaders = t.getRequestHeaders();
            Set<Map.Entry<String, List<String>>> entries = requestHeaders.entrySet();


            URL uri = null;
            try {
                uri = new URL(url);
            } catch (Exception e) {
                e.printStackTrace();
            }


            Headers responseHeaders = t.getResponseHeaders();
            Response response = sendRequest(uri, entries);


            byte[] bytes = response.body().bytes();
            if (needInject && response.isSuccessful()) {
                bytes = injectJavaScript(bytes, uri.getProtocol() + "://" + uri.getHost());
            }


            okhttp3.Headers headers = response.headers();

            Map<String, List<String>> stringListMap = headers.toMultimap();

            stringListMap.forEach(new BiConsumer<String, List<String>>(){
                @Override
                public void accept(String key, List<String> values) {
                    key = key.toLowerCase();
                    /**
                     * 日期自带；要允许iframe；一次性发送数据，所有不使用transfer-encoding
                     *
                     * */
                    if ("date".equals(key) || "x-frame-options".equals(key) || "transfer-encoding".equals(key)) {

                    } else {
                        responseHeaders.put(key, values);
                    }
                }
            });

            t.sendResponseHeaders(response.code(), bytes.length);
            OutputStream os = t.getResponseBody();
            os.write(bytes);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void testHandler(HttpExchange t) {
        try {
            byte[] bytes = tempHtml();
            bytes = injectJavaScript(bytes, "");
            Headers responseHeaders = t.getResponseHeaders();


            responseHeaders.set("content-type", "text/html; charset=UTF-8");

            t.sendResponseHeaders(200, bytes.length);
            OutputStream os = t.getResponseBody();
            os.write(bytes);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    byte[] injectJavaScript(byte[] oldBody, String origin) {

        Document document = Jsoup.parse(new String(oldBody));
        Element head = document.head();

        Element scriptLink = new Element("script");
        //scriptLink.attr("src", "http://locinstall.js");
        scriptLink.text("if ('serviceWorker' in navigator) {\n" +
                "    navigator.serviceWorker.startMessages();\n" +
                "    navigator.serviceWorker.register('service-worker.js', {scope: './'})\n" +
                "        .then(function(registration) {\n" +
                "        }).catch(function(error) {\n" +
                "        console.log(error);\n" +
                "    });\n" +
                "} else {\n" +
                "    console.log(\"没有serviceWorker API\");" +
                "\n" +
                "}");

        head.insertChildren(0, scriptLink);
        // String s = document.toString();
        // System.out.println(s);
        return document.toString().getBytes();
    }


    public byte[] tempHtml() {
        String html = "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <title>爬虫订阅</title>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n" +
                "    <link rel=\"stylesheet\" href=\"/css/normalize.css\">\n" +
                "    <script src=\"/js/vue.js\"></script>\n" +
                "</head>\n" +
                "<body>\n" +
                " 你看到我了\n" +
                "</body>\n" +
                "</html>";
        byte[] bytes = html.getBytes();
        return bytes;
    }


    public static void main(String[] args) {
        RedirectRequestHandler redirectRequestHandler = new RedirectRequestHandler();
//        try {
//            Response response = redirectRequestHandler.sendRequest("https://www.cnblogs.com/huaweiyun/", new HashSet<>());
//
//            String string = response.body().string();
//            System.out.println(string);
//            response.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }

    private Response sendRequest(URL url, Set<Map.Entry<String, List<String>>> headers) throws IOException {
        okhttp3.Headers.Builder builder = new okhttp3.Headers.Builder();
        for (Map.Entry<String, List<String>> header : headers) {
            List<String> value = header.getValue();
            String key = header.getKey().toLowerCase();
            if (value.size() < 1) {
                continue;
            }
            if (value.size() > 1) {
                System.out.println(value.toString());
            }

            if ("accept-encoding".equals(key)) {
                continue;
            }
            if ("host".equals(key)) {
                builder.add(key, url.getHost());
            } else if ("referer".equals(key)) {
                builder.add(key, url.getProtocol() + "://" + url.getHost());
            } else {
                builder.add(key, value.get(0));
            }


        }


        Request request = new Request.Builder()
                .url(url)
                .headers(builder.build())
                .build();

        try {
            Response response = client.newCall(request).execute();
//            if (!response.isSuccessful()) {
//                throw new IOException("Unexpected code " + response);
//            }

            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

}
